package com.tool_stdy.IO.NIO;

import com.google.common.collect.Maps;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * Created by yan_li on 2017/1/10.
 */
public class NIOServerTest {

    ServerSocketChannel server;

    Selector selector;

    ByteBuffer receive = ByteBuffer.allocate(1024);
    ByteBuffer send = ByteBuffer.allocate(1024);

    //用于模拟接受的消息返回
    Map<SelectionKey, String> maps = Maps.newHashMap();

    public NIOServerTest(int port) throws IOException {
        server = ServerSocketChannel.open();
        server.socket().bind(new InetSocketAddress(8080));
        //手动设置为非阻塞
        server.configureBlocking(false);
        selector = Selector.open();
        //准备就绪，将通道注册到selector上，并监听阻塞状态
        server.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("NIO 服务已经启动,监听端口是:" + port);
    }

    public static void main(String[] args) throws IOException {
        new NIOServerTest(8080).listener();
    }

    public void listener() throws IOException {
        while (true) {//轮询
            //判断当前有没有客户端注册，让多路复用器开始监听
            int i = selector.select();
            if (i == 0) {//如果没有，那么继续轮询
                continue;
            }
            //这个set集合就是注册到这个selector上的channel
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            for (Iterator<SelectionKey> iterator = selectionKeys.iterator(); iterator.hasNext(); ) {
                SelectionKey key = iterator.next();
                process(key);
                iterator.remove();
            }
        }
    }

    private void process(SelectionKey key) throws IOException {
        //判断用户有没有跟Server建立好链接
        if (key.isAcceptable()) {
            SocketChannel client = server.accept();
            client.configureBlocking(false);
            client.register(selector, SelectionKey.OP_READ);
        } else if (key.isReadable()) {//判断是否可以读数据
            receive.clear();
            SocketChannel channel = (SocketChannel) key.channel();
            int readLen = channel.read(receive);
            if (readLen > 0) {
                String msg = new String(receive.array(), 0, readLen);
                System.out.println("获取客户端发送的消息:" + msg);
                maps.put(key, msg);
                //将本管道设置为可写
                channel.register(selector, SelectionKey.OP_WRITE);
            }
        } else if (key.isWritable()) { //判断是否可以写数据了
            if (!maps.containsKey(key)) {
                return;
            }
            SocketChannel client = (SocketChannel) key.channel();
            send.clear();
            send.put(new String(maps.get(key) + " ,您好 您的请求已处理完成").getBytes());
            send.flip();
            client.write(send);
            client.register(selector, SelectionKey.OP_READ);
        }


    }

//    public static void main(String[] args) {
//        List<String> list = Lists.newArrayList();
//        list.add("aa");
//        list.add("bb");
//        list.add("c");
//        for(Iterator<String> it= list.iterator();it.hasNext();){
//            System.out.println(it.next());
//        }
//    }
}
